iT邦幫忙

2023 iThome 鐵人賽

DAY 20
0
Mobile Development

Android Studio 30天進階學習系列 第 20

Android Studio 30天進階學習-DAY20_JetpackCompose的跳轉功能NavHost

  • 分享至 

  • xImage
  •  

今天要來說明如何在Compose中進行基本的跳換頁面的動作功能。

說是跳轉頁面,但事實上偏向Java、Kotlin中的Fragment功能類似,需要一個觸發按鈕來運作。

這邊會先從簡易的跳轉頁面開始實作說明,後面還有進階一些的跳轉撰寫方法。

建立新Compose畫面

這邊依照以下步驟進行新增。

  1. 圖1. 到檔案資料夾點擊滑鼠右鍵->New->Compose->Empty Activity
  2. 點擊後會到 圖2. 頁面,之後進行命名後點擊Finish即可成功建立。

圖1.

https://ithelp.ithome.com.tw/upload/images/20230930/20150370n0sO3HT6DW.png

圖2.

https://ithelp.ithome.com.tw/upload/images/20230930/20150370nBiNR7lw5w.png

Navigation

Navigation3 大主要部分是 NavControllerNavGraphNavHost
這是今天跳換頁面會用到的功能。

NavHost的參數

今天會以NavHoststartDestinationnavController參數來建成一個極簡的跳轉功能,並會搭配NavGraphBuilder.composable來組成頁面跳轉。

  • 參數說明:
    • navControllerNavHostController 對象,用於管理和控制導覽操作。 它負責追蹤當前的導航狀態以及執行導航操作,如 navigatepopBackStack 等。
    • startDestination:這個是起始的畫面,用來建立初始顯示畫面路由會導向哪個function。
    • modifierModifier 對象,用於定義 NavHost 的修飾符。
    • contentAlignment:內容的對齊方式,用於定義內容在 NavHost 中的對齊方式,例如 Alignment.CenterAlignment.TopStart 等等的排列參數。
    • route:可選參數,表示目前 NavHost 所在的路由。 通常情況下,您不需要指定此參數,因為 NavHost 通常是根層級的,但在某些情況下,可以使用它來嵌套多個 NavHost
    • enterTransition:進入動畫的定義。 它是一個 Lambda 函數,用於定義當導航到新目標時應用的進入動畫。
    • exitTransition:退出動畫的定義。 它是一個 Lambda 函數,用於定義當從當前目標導航到新目標時應用的退出動畫。
    • popEnterTransition:彈出進入動畫的定義。 它是一個 Lambda 函數,用於定義當從後退堆疊中的目標導航回當前目標時應用的進入動畫。
    • popExitTransition:彈出退出動畫的定義。 它是一個 Lambda 函數,用於定義當從後退堆疊中的目標導航回當前目標時應用的退出動畫。
    • builder:一個 Lambda 函數,用來建立導航圖。 在這裡,您可以使用 NavGraphBuilder 物件來定義導航目標和路由之間的關係,以及每個目標的內容。

以上是所有的NavHost參數說明,今天只會使用到前面兩個參數來建立簡易的跳轉功能。

@Composable
@ComposableTarget
public fun NavHost(
    navController: NavHostController,
    startDestination: String,
    modifier: Modifier = COMPILED_CODE,
    contentAlignment: Alignment = COMPILED_CODE,
    route: String? = COMPILED_CODE,
    enterTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition = COMPILED_CODE,
    exitTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition = COMPILED_CODE,
    popEnterTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition = COMPILED_CODE,
    popExitTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition = COMPILED_CODE,
    builder: NavGraphBuilder.() -> Unit
): Unit

撰寫的格式

這邊起始畫面為MainActivity,接著建立個跳轉頁面的方法及跳轉目的地。

NavHost(navController = navController,
        startDestination = "mainActivity") {
    composable("mainActivity") { GreetingBackground() }
    composable("homepage") { Background() }
    composable("searchActivity") { SearchBackground() }
    composable("profileActivity") { ProfileBackground() }
    composable("settingActivity") { SettingBackground() }
}

修改主頁面的底部導覽條

// 讓跳轉重複點擊只會有單次挑轉,不會有反覆恆跳的感覺出現,也就是當我們每次點擊時都會先跳回主畫面在進行跳轉,但當我們。
fun NavHostController.navigateSingleTopTo(route: String) =
    this.navigate(route) { launchSingleTop = true }

@Composable
private fun BottomNavigation(modifier: Modifier = Modifier, context:Context) {
    val navController = rememberNavController()
    val homeBool = remember {mutableStateOf(false)}
    val menuBool = remember {mutableStateOf(false)}
    val searchBool = remember {mutableStateOf(false)}
    val profileBool = remember {mutableStateOf(false)}
    val settingBool = remember {mutableStateOf(false)}
    
    NavHost(navController = navController,
            startDestination = "mainActivity") {
        composable("mainActivity") { GreetingBackground() }
        composable("homepage") { Background() }
        composable("searchActivity") { SearchBackground() }
        composable("profileActivity") { ProfileBackground() }
        composable("settingActivity") { SettingBackground() }
    }
    Row (modifier = Modifier.fillMaxHeight()){
        NavigationBar(
            //...省略
        ){
            // Menu
            NavigationBarItem(
                // 判斷是否有選擇,因起始畫面為menu所以反向為true。
                selected = !menuBool.value,
                onClick = {
                    // 將其餘選項關閉,由於menu是反向所以false
                    false.also { menuBool.value = it }
                    false.also { homeBool.value = it }
                    false.also { searchBool.value = it }
                    false.also { profileBool.value = it }
                    false.also { settingBool.value = it }
                    Log.e(TAG, "SootheBottomNavigation: Home" )
                    // 利用建立的.navigateSingleTopTo來達到單次跳轉至指定頁面。
                    navController.navigateSingleTopTo("MainActivity")
                    Toast.makeText(context, "Home", Toast.LENGTH_SHORT).show()
                },
                // 其餘參數調整部分省略
            )
            
            // Home
            NavigationBarItem(
                // 判斷是否有選擇,因起始畫面為menu所以反向為true。
                selected = homeBool.value,
                onClick = {
                    true.also { menuBool.value = it }
                    true.also { homeBool.value = it }
                    false.also { searchBool.value = it }
                    false.also { profileBool.value = it }
                    false.also { settingBool.value = it }
                    Log.e(TAG, "SootheBottomNavigation: Home" )
                    navController.navigateSingleTopTo("homepage")
                    Toast.makeText(context, "Home", Toast.LENGTH_SHORT).show()
                },
                // 其餘參數調整部分省略
            )
            
            // Search
            NavigationBarItem(
                // 判斷是否有選擇,因起始畫面為menu所以反向為true。
                selected = searchBool.value,
                onClick = {
                    true.also { menuBool.value = it }
                    false.also { homeBool.value = it }
                    true.also { searchBool.value = it }
                    false.also { profileBool.value = it }
                    false.also { settingBool.value = it }
                    navController.navigateSingleTopTo("searchActivity")
                    Log.e(TAG, "SootheBottomNavigation: Search" )
                    Toast.makeText(context, "Search", Toast.LENGTH_SHORT).show()
                }
                // 其餘參數調整部分省略
            )
            
            // Profile
            NavigationBarItem(
                // 判斷是否有選擇,因起始畫面為menu所以反向為true。
                selected = profileBool.value,
                onClick = {
                    true.also { menuBool.value = it }
                    false.also { homeBool.value = it }
                    false.also { searchBool.value = it }
                    true.also { profileBool.value = it }
                    false.also { settingBool.value = it }
                    navController.navigateSingleTopTo("profileActivity")
                    Log.e(TAG, "SootheBottomNavigation: Account" )
                    Toast.makeText(context, "Account", Toast.LENGTH_SHORT).show()
                }
                // 其餘參數調整部分省略
            )
            
            // Setting
            NavigationBarItem(
                // 判斷是否有選擇,因起始畫面為menu所以反向為true。
                selected = settingBool.value,
                onClick = {
                    true.also { menuBool.value = it }
                    false.also { homeBool.value = it }
                    false.also { searchBool.value = it }
                    false.also { profileBool.value = it }
                    true.also { settingBool.value = it }
                    navController.navigateSingleTopTo("settingActivity")
                    Log.e(TAG, "SootheBottomNavigation: Settings" )
                    Toast.makeText(context, "Setting", Toast.LENGTH_SHORT).show()
                }
                // 其餘參數調整部分省略
            )
        }
    }
}

以上是在主頁面的底部導覽條功能修改,接著就是撰寫其他跳轉後的頁面布置了,這邊就以一個去做程式碼展示,因為各自跳轉的需求不同,有不同的頁面配置。

Setting頁面布置

@Composable
fun SettingsSelect() {
    val context = LocalContext.current
    Column (Modifier.fillMaxWidth()){
        Text(text = "設定",
            Modifier
                .padding(10.dp)
                .fillMaxWidth()
                .align(Alignment.CenterHorizontally),
            fontSize = MaterialTheme.typography.headlineLarge.fontSize,
            fontStyle = MaterialTheme.typography.headlineLarge.fontStyle,
            textAlign = MaterialTheme.typography.headlineLarge.textAlign,
            color = MaterialTheme.colorScheme.onBackground)
        ElevatedButton(onClick = {
            Toast.makeText(context, "SelfInfo Modify!", Toast.LENGTH_SHORT).show()
        },Modifier.fillMaxWidth()) {
            Icon(imageVector = Icons.Default.AccountCircle,
                contentDescription = null)
            Text(text = "個人資料修改")
        }
        ElevatedButton(onClick = {
            Toast.makeText(context, "Schedule", Toast.LENGTH_SHORT).show()
        },Modifier.fillMaxWidth()) {
            Icon(imageVector = Icons.Default.DateRange,
                contentDescription = null)
            Text(text = "行事曆")
        }
        ElevatedButton(onClick = {
            Toast.makeText(context, "password reset!", Toast.LENGTH_SHORT).show()
        },Modifier.fillMaxWidth()) {
            Icon(imageVector = Icons.Default.Lock,
                contentDescription = null)
            Text(text = "密碼重製")
        }
        ElevatedButton(onClick = {
            Toast.makeText(context, "Logout your account!", Toast.LENGTH_SHORT).show()
            Log.e(TAG, "SettingsSelect: Logout your account!" )
        },Modifier.fillMaxWidth()) {
            Icon(imageVector = Icons.Default.ExitToApp,
                contentDescription = null)
            Text(text = "登出")
        }
    }
}

@Composable
fun SettingBackground(){
    Box(modifier = Modifier
        .fillMaxSize()
        .background(MaterialTheme.colorScheme.background)) {
        Column (Modifier.padding(10.dp)){
            SettingsSelect()
        }
    }
}
  • 預覽展示
    因為底部導覽條還會存在,所以這邊不需要再撰寫一份導覽條程式碼。
    https://ithelp.ithome.com.tw/upload/images/20230930/20150370nTEMknyPrW.png

結果展示

這邊展示了五個頁面橫向跳轉,並包含一個跳轉過程的截圖。

  • Menu頁面
    https://ithelp.ithome.com.tw/upload/images/20230930/201503700DW25IqeSz.jpg
  • Home頁面
    https://ithelp.ithome.com.tw/upload/images/20230930/201503702sx9rdyAzs.jpg
  • Search頁面
    https://ithelp.ithome.com.tw/upload/images/20230930/20150370vLnL4fNbxQ.jpg
  • Profile頁面
    https://ithelp.ithome.com.tw/upload/images/20230930/20150370sytSpruTjm.jpg
  • Setting頁面
    https://ithelp.ithome.com.tw/upload/images/20230930/20150370wX4B0OovCd.jpg

總結

以上是今天關於Navigation的跳轉功能實作與說明,也能看到因為改了點擊的布林變數的變換,所以底下的導覽條會根據目前所在的頁面一同更改selected參數的是否。


上一篇
Android Studio 30天進階學習-DAY19_JetpackCompose替原件放上動態顯示功能(AnimatedVisibility的功能說明)
下一篇
Android Studio 30天進階學習-DAY21_JetpackCompose側邊導覽條(NavigationRail說明)
系列文
Android Studio 30天進階學習30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言